﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using TradeSeaShared;

using System.Threading;
using System.Reflection;
using System.Diagnostics;

using Lidgren.Network;

namespace TradeSea
{
    class TradeSeaNetClient : INet
    {
        public static TradeSeaNetClient Singilton;

        public static string NetClientHostName = "127.0.0.1";

        private Dictionary<int, MethodInfo> PacketHandles = new Dictionary<int, MethodInfo>();

        public NetClient Client;

        public Stopwatch boatUpdate = new Stopwatch();

        public bool Connected
        {
            get { return this.Client.ConnectionStatus == NetConnectionStatus.Connected; }
        }

        public static void Init()
        {
            if (Singilton != null)
            {
                return;
            }
            Singilton = new TradeSeaNetClient();
            Thread netThread = new Thread(new ThreadStart(Singilton.NetLoop));
            netThread.IsBackground = true;
            netThread.Start();
        }

        public void NetLoop()
        {
            this.Client = new NetClient(Singiltons.ClientNetConfig);

            foreach (MethodInfo item in new ClientPackets().GetType().GetMethods(BindingFlags.Static | BindingFlags.Public))
            {
                this.PacketHandles.Add(((PacketAttribute)(item.GetCustomAttributes(false)[0])).ID, item);
            }

            Singiltons.Log("Network", "Starting Client");
            this.Client.Start();
            if (Singiltons.IsListen)
            {
                Thread.Sleep(500); // Give the server some time
                this.Client.Connect("127.0.0.1", Singiltons.ApplicationPort);
            }
            else
            {
                this.Client.Connect(NetClientHostName, Singiltons.ApplicationPort);
            }
            while (true)
            {
                NetIncomingMessage msg = this.Client.ReadMessage();
                if (msg == null)
                {
                    if (boatUpdate.ElapsedMilliseconds > 250)
                    {
                        SendBoatUpdate();
                        boatUpdate.Restart();
                    }
                    Thread.Sleep(0);
                    continue;
                }
                switch (msg.MessageType)
                {
                    case NetIncomingMessageType.Data:
                        int id = msg.ReadInt32();
                        if (PacketHandles.ContainsKey(id))
                        {
                            PacketHandles[id].Invoke(null, new object[] { msg, this });
                        }
                        break;
                    case NetIncomingMessageType.StatusChanged:
                        Singiltons.Log("Client Network", "Server Status Changed to : " + msg.SenderConnection.Status.ToString());
                        if (msg.SenderConnection.Status == NetConnectionStatus.Connected)
                        {
                            if (msg.SenderConnection.RemoteHailMessage != null)
                            {
                                // we now have a seed to seed the world with, time for a cross thread call
                                int seed = msg.SenderConnection.RemoteHailMessage.ReadInt32();
                                Singiltons.Log("Client Seed", seed);
                                MainGame.GameWorld.NewSeed(seed);
                                boatUpdate.Start();
                            }
                        }
                        break;
                    case NetIncomingMessageType.WarningMessage:
                    case NetIncomingMessageType.ErrorMessage:
                        Singiltons.Log("Client Network Message", msg.ReadString());
                        break;
                    default:
                        Singiltons.Log("Client Network", "Packet Not Handled : " + msg.MessageType.ToString());
                        break;
                }

                Thread.Sleep(0); // This gives the operating system some time, 
                // other wise this would eat a entire core for no reason
            }
        }

        public void SendBoatUpdate()
        {
            NetOutgoingMessage msg = CreateMessage(2);
            if (MainGame.playerboat == null)
            {
                return;
            }
            msg.Write(MainGame.playerboat.rudderAngle);
            msg.Write(MainGame.playerboat.yardAngle);
            SendMessage(msg, null);
        }

        public void SendMessage(NetOutgoingMessage message, NetConnection to)
        {
            this.Client.SendMessage(message, NetDeliveryMethod.ReliableOrdered);
        }

        public NetOutgoingMessage CreateMessage(int id)
        {
            NetOutgoingMessage ret = this.Client.CreateMessage();
            ret.Write(id);
            return ret;
        }

        public void SendMessageToAll(NetOutgoingMessage message)
        {
            throw new NotImplementedException();
        }
    }
}
